package com.mdd.front.service.order.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.yulichang.query.MPJQueryWrapper;
import com.mdd.common.config.GlobalConfig;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.course.Course;
import com.mdd.common.entity.course.StudyCourse;
import com.mdd.common.entity.order.*;
import com.mdd.common.entity.system.SystemConfig;
import com.mdd.common.entity.user.User;
import com.mdd.common.enums.AccountChangeEnum;
import com.mdd.common.enums.ClientEnum;
import com.mdd.common.enums.OrderEnum;
import com.mdd.common.enums.OrderLogEnum;
import com.mdd.common.mapper.course.CourseMapper;
import com.mdd.common.mapper.order.*;
import com.mdd.common.mapper.system.SystemConfigMapper;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.utils.*;
import com.mdd.front.LikeFrontThreadLocal;
import com.mdd.front.config.wxpay.WxPayProperties;
import com.mdd.front.service.IUserService;
import com.mdd.front.service.order.IOrderService;
import com.mdd.front.service.order.IRechargeOrderService;
import com.mdd.front.service.system.ISystemDevPayService;
import com.mdd.front.utils.WxPayServiceUtil;
import com.mdd.front.validate.OrderParam;
import com.mdd.front.validate.PageParam;
import com.mdd.front.validate.RechargeOrderParam;
import com.mdd.front.vo.order.OrderDetailVo;
import com.mdd.front.vo.order.OrderListVo;
import com.mdd.front.vo.order.RechargeOrderDetailVo;
import com.mdd.front.vo.order.RechargeOrderListVo;
import com.mdd.front.vo.system.SystemDevWxPayConfig;
import com.mdd.front.vo.user.UserInfoVo;
import com.mdd.front.vo.wxpay.WxPayCreateOrderRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 订单实现类
 * @author panweiliang
 */
@Service
public class RechargeOrderServiceImpl implements IRechargeOrderService {

    final Logger log = LoggerFactory.getLogger(this.getClass());
        
    @Resource
    RechargeOrderMapper rechargeOrderMapper;

    @Resource
    OrderMapper orderMapper;

    @Resource
    IUserService userService;

    @Resource
    AccountLogMapper accountLogMapper;

    @Resource
    private SystemConfigMapper systemConfigMapper;

    private String getAppId() {
        List<SystemConfig> configs = systemConfigMapper.selectList(
                new QueryWrapper<SystemConfig>()
                        .select("id", "type", "name", "value")
                        .eq("type", "mp_channel"));
        Map<String, String> map = new LinkedHashMap<>();
        for (SystemConfig config : configs) {
            map.put(config.getName(), config.getValue());
        }
        return map.getOrDefault("appId", "");
    }
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

    @Override
    public RechargeOrderDetailVo getDetailById(Integer id) {
        RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(id);
        RechargeOrderDetailVo rechargeOrderDetailVo = new RechargeOrderDetailVo();

        BeanUtils.copyProperties(rechargeOrder, rechargeOrderDetailVo);

        rechargeOrderDetailVo.setPayTime(TimeUtil.timestampToDate(rechargeOrder.getPayTime()));

        return rechargeOrderDetailVo;
    }

    @Override
    public RechargeOrder getById(Integer id) {
        RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(id);
        return rechargeOrder;
    }

    @Override
    public RechargeOrder updateSn(Integer id) {
       RechargeOrder rechargeOrder = rechargeOrderMapper.selectById(id);
       org.springframework.util.Assert.notNull(rechargeOrder, "充值订单不存在");
        rechargeOrder.setSn(randMakeOrderSn());
        rechargeOrder.setPayWay(OrderEnum.ORDER_PAY_WAY_WX.getCode());
       this.rechargeOrderMapper.updateById(rechargeOrder);
       return rechargeOrder;
    }

    /**
     * 订单新增
     *
     * @author panweiliang
     * @param rechargeOrderParam 参数
     */
    @Override
    public RechargeOrderDetailVo add(RechargeOrderParam rechargeOrderParam) throws WxPayException {

        String cancelUnpaidOrders = LsConfigUtil.get("transaction", "cancel_unpaid_orders");

        String cancelUnpaidOrdersTimesStr = LsConfigUtil.get("transaction", "cancel_unpaid_orders_times", "30");

        RechargeOrderDetailVo detail = new RechargeOrderDetailVo();
        RechargeOrder model = new RechargeOrder();
        model.setSn(this.randMakeOrderSn());
        model.setTransactionId(null);
        model.setUserId(rechargeOrderParam.getUserId());
        model.setTerminal(rechargeOrderParam.getTerminal());
        model.setPayStatus(OrderEnum.PAY_STATUS_UNPAID.getCode());
        model.setPayWay(OrderEnum.ORDER_PAY_WAY_WX.getCode());
        model.setPayTime(null);
        model.setOrderAmount(rechargeOrderParam.getOrderAmount());
        model.setCreateTime(TimeUtil.timestamp());
        model.setUpdateTime(TimeUtil.timestamp());
        rechargeOrderMapper.insert(model);

        if ("1".equals(cancelUnpaidOrders)) {
            Long cancelUnpaidOrdersTimes = Long.parseLong(cancelUnpaidOrdersTimesStr);
            Long orderExpireTime = model.getUpdateTime() * 1000 + cancelUnpaidOrdersTimes * 60 * 1000;
            detail.setCancelUnpaidOrders(true);
            detail.setOrderExpireTime(orderExpireTime);
        } else {
            detail.setCancelUnpaidOrders(false);
            detail.setOrderExpireTime(0l);
        }

        BeanUtils.copyProperties(model, detail);
        return detail;
    }

    /**
     * 生成唯一订单号
     *
     * @author panweiliang
     * @return Integer
     */
    private String randMakeOrderSn() {
        String sn;
        while (true) {
            sn = ToolsUtil.randomDigitString(18);
            Order snModel = orderMapper.selectOne(new QueryWrapper<Order>()
                    .select("id")
                    .eq("sn", sn)
                    .last("limit 1"));
            if (snModel == null) {
                break;
            }
        }
        return sn;
    }

    @Override
    public boolean updateOrderStatusToPaid(String outTradeNo, String transactionId) {
        RechargeOrder order = this.rechargeOrderMapper.selectOne(
                new QueryWrapper<RechargeOrder>()
                        .eq("sn", outTradeNo)
                        .last("limit 1"));
        log.info("订单状态:" + order.toString());
        try {
            if (order != null && OrderEnum.PAY_STATUS_UNPAID.getCode() == (order.getPayStatus() != null ? order.getPayStatus().intValue() : 0)) {

                Integer userId = order.getUserId();
                WxPayService wxService = WxPayServiceUtil.handler(String.valueOf(ClientEnum.MNP.getCode()));
                WxPayOrderQueryV3Result wxPayOrderQueryV3Result = wxService.queryOrderV3(transactionId, outTradeNo);
                String tradeState = wxPayOrderQueryV3Result.getTradeState();
                transactionId = wxPayOrderQueryV3Result.getTransactionId();
                if ("SUCCESS".equals(tradeState)) {
                    order.setTransactionId(transactionId);
                    order.setPayStatus(OrderEnum.PAY_STATUS_PAID.getCode());
                    order.setUpdateTime(TimeUtil.timestamp());
                    order.setPayTime(TimeUtil.timestamp());
                    order.setPayWay(OrderEnum.ORDER_PAY_WAY_WX.getCode());
                    this.rechargeOrderMapper.updateById(order);
                    BigDecimal orderAmount = order.getOrderAmount();
                    orderAmount = orderAmount != null ? orderAmount : new BigDecimal("0");

                    User user = userService.getById(userId);
                    if (user != null) {
                        BigDecimal userMoney = user.getUserMoney();
                        userMoney = userMoney != null ? userMoney : new BigDecimal("0");
                        userMoney = userMoney.add(orderAmount);
                        user.setUserMoney(userMoney);
                        this.userService.updateById(user);
                        AccountLog accountLog = new AccountLog();
                        accountLog.setUserId(userId);
                        accountLog.setChangeAmount(orderAmount);
                        accountLog.setChangeType(AccountChangeEnum.BNW_INC_RECHARGE.getCode());
                        accountLog.setRemark("用户充值");
                        accountLog.setLeftAmount(userMoney);
                        accountLog.setAction(AccountChangeEnum.ACTION_INC.getCode());
                        accountLog.setAssociationSn(order.getSn());
                        accountLog.setSn(order.getTransactionId());
                        accountLog.setCreateTime(TimeUtil.timestamp());
                        accountLog.setUpdateTime(TimeUtil.timestamp());
                        this.accountLogMapper.insert(accountLog);
                    }
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("异常:", e);
            log.info("异常:", e.getMessage());
        }

        return false;
    }

    @Override
    public boolean updateOrderPayStatusToPaid(Integer rechargeOrderId) throws WxPayException {
        RechargeOrder rechargeOrder = this.rechargeOrderMapper.selectById(rechargeOrderId);
        Assert.notNull(rechargeOrder, "订单数据不存在");
        return this.updateOrderStatusToPaid(rechargeOrder.getSn(), null);
    }

    @Override
    public PageResult<RechargeOrderListVo> list(PageParam pageParam, Integer userId) {


        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();

        QueryWrapper<RechargeOrder> queryWrapper = new QueryWrapper<RechargeOrder>()
                .eq("user_id", userId)
                .eq("pay_status", OrderEnum.PAY_STATUS_PAID.getCode())
                .isNull("delete_time")
                .orderByDesc(Arrays.asList("update_time"));

        IPage<RechargeOrder> iPage = rechargeOrderMapper.selectPage(new Page<>(page, limit), queryWrapper);
        List<RechargeOrderListVo> result = new LinkedList<>();
        for(RechargeOrder item : iPage.getRecords()) {
            RechargeOrderListVo vo = new RechargeOrderListVo();
            BeanUtils.copyProperties(item, vo);
            vo.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
            result.add(vo);
        }
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), result);

    }
}
